import time
import json
import asyncio
from typing import Optional
from fastapi import Request
from starlette.middleware.base import BaseHTTPMiddleware
from starlette.types import ASGIApp
from starlette.responses import Response
from app.models.log_models import RequestLog
from jose import jwt, JWTError
from app.core.config import settings
import logging

logger = logging.getLogger(__name__)

class RequestLoggerMiddleware(BaseHTTPMiddleware):
    """请求日志中间件 - 优化版本，避免阻塞请求"""
    
    def __init__(self, app: ASGIApp):
        super().__init__(app)
    
    async def dispatch(self, request: Request, call_next):
        # 记录请求开始时间
        start_time = time.time()
        
        # 检查是否需要跳过日志记录
        if self._should_skip_logging(request):
            return await call_next(request)
        
        # 提取基本请求信息（不读取请求体，避免干扰请求处理）
        ip_address = self._get_client_ip(request)
        user_agent = request.headers.get("user-agent", "未知")
        username = self._extract_username_from_token(request)
        
        # 处理请求
        response = await call_next(request)
        
        # 计算响应时间
        process_time = (time.time() - start_time) * 1000
        
        # 异步记录日志，不阻塞响应
        asyncio.create_task(
            self._log_request_async(
                request, response, ip_address, user_agent, 
                username, process_time
            )
        )
        
        return response
    
    def _should_skip_logging(self, request: Request) -> bool:
        """判断是否应该跳过日志记录"""
        path = request.url.path
        
        # 跳过静态文件和特定路径
        skip_paths = ["/static", "/docs", "/openapi", "/favicon.ico"]
        if any(path.startswith(skip_path) for skip_path in skip_paths):
            return True
        
        # 跳过根路径
        if path == "/":
            return True
        
        # 跳过OPTIONS请求
        if request.method == "OPTIONS":
            return True
            
        return False
    
    def _get_client_ip(self, request: Request) -> str:
        """获取客户端IP地址"""
        # 优先从代理头获取
        forwarded_for = request.headers.get("x-forwarded-for")
        if forwarded_for:
            return forwarded_for.split(",")[0].strip()
        
        # 从其他代理头获取
        real_ip = request.headers.get("x-real-ip")
        if real_ip:
            return real_ip.strip()
        
        # 最后使用客户端IP
        return request.client.host if request.client else "未知"
    
    def _extract_username_from_token(self, request: Request) -> Optional[str]:
        """从JWT token中提取用户名"""
        try:
            authorization = request.headers.get("Authorization")
            if not authorization or not authorization.startswith("Bearer "):
                return None
            
            token = authorization[7:]  # 移除 "Bearer " 前缀
            payload = jwt.decode(
                token, 
                settings.SECRET_KEY, 
                algorithms=[settings.ALGORITHM]
            )
            return payload.get("sub")
            
        except JWTError:
            return None
        except Exception as e:
            logger.warning(f"提取用户名时发生错误: {str(e)}")
            return None
    
    async def _log_request_async(
        self, 
        request: Request, 
        response: Response,
        ip_address: str,
        user_agent: str,
        username: Optional[str],
        process_time: float
    ):
        """异步记录请求日志"""
        try:
            await RequestLog.create(
                user_id=None,
                username=username,
                ip_address=ip_address,
                method=request.method,
                path=request.url.path,
                status_code=response.status_code,
                response_time=process_time,
                user_agent=user_agent,
                request_body=None,  # 暂时不记录请求体，避免干扰请求处理
                response_body=None  # 暂时不记录响应体，避免干扰响应处理
            )
            
        except Exception as e:
            # 记录日志失败不应影响正常请求
            logger.error(f"记录请求日志失败: {str(e)}")